/**
 * <p>
 * 实现功能：javascript工具类
 * <p/>
 *
 * @author 秦有宝
 * @version 1.0.00
 *
 * <p>
 * 功能：
 *      addNum：加法运算
 *      Base64：Base64编码
 *      dateFormat：日期格式化
 *      getPreMonth：获取上一个月
 *      getNextMonth：获取下一个月
 *      dateCompare：日期比较
 *      uuid: uuid
 *      number：数值计算
 *      几个常用字符串hash算法的: hashCode sdbmCode djb2Code loseCode
 *      计算代码耗时
 *      通过汇率计算
 * <p/>
 *
 */
MyUtils ={
    /*
     *   加法运算
     */
    addNum: function (num1, num2) {
        var r1, r2, m, c;
        try { r1 = num1.toString().split(".")[1].length; } catch (e) { r1 = 0; }
        try { r2 = num2.toString().split(".")[1].length; } catch (e) { r2 = 0; }
        c = Math.abs(r1 - r2);
        m = Math.pow(10, Math.max(r1, r2));
        if (c > 0) {
            var cm = Math.pow(10, c);
            if (r1 > r2) {
                num1 = Number(num1.toString().replace(".", ""));
                num2 = Number(num2.toString().replace(".", "")) * cm;
            } else {
                num1 = Number(num1.toString().replace(".", "")) * cm;
                num2 = Number(num2.toString().replace(".", ""));
            }
        } else {
            num1 = Number(num1.toString().replace(".", ""));
            num2 = Number(num2.toString().replace(".", ""));
        }
        return (num1 + num2) / m;
    },
    /*
     *   Base64编码
     */
    Base64: function () {
        // private property
        var keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
        // public method for encoding
        var utf8Encode;
        this.encode = function (input) {
            var output = "";
            var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
            var i = 0;
            input = utf8Encode(input.toString());
            while (i < input.length) {
                chr1 = input.charCodeAt(i++);
                chr2 = input.charCodeAt(i++);
                chr3 = input.charCodeAt(i++);
                enc1 = chr1 >> 2;
                enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
                enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
                enc4 = chr3 & 63;
                if (isNaN(chr2)) {
                    enc3 = enc4 = 64;
                } else if (isNaN(chr3)) {
                    enc4 = 64;
                }
                output = output +
                    keyStr.charAt(enc1) + keyStr.charAt(enc2) +
                    keyStr.charAt(enc3) + keyStr.charAt(enc4);
            }
            return output;
        };

        // public method for decoding
        var utf8Decode;
        this.decode = function (input) {
            var output = "";
            var chr1, chr2, chr3;
            var enc1, enc2, enc3, enc4;
            var i = 0;
            input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
            while (i < input.length) {
                enc1 = keyStr.indexOf(input.charAt(i++));
                enc2 = keyStr.indexOf(input.charAt(i++));
                enc3 = keyStr.indexOf(input.charAt(i++));
                enc4 = keyStr.indexOf(input.charAt(i++));
                chr1 = (enc1 << 2) | (enc2 >> 4);
                chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
                chr3 = ((enc3 & 3) << 6) | enc4;
                output = output + String.fromCharCode(chr1);
                if (enc3 != 64) {
                    output = output + String.fromCharCode(chr2);
                }
                if (enc4 != 64) {
                    output = output + String.fromCharCode(chr3);
                }
            }
            output = utf8Decode(output);
            return output;
        };

        // private method for UTF-8 encoding
        utf8Encode = function (string) {
            string = string.replace(/\r\n/g, "\n");
            var utftext = "";
            for (var n = 0; n < string.length; n++) {
                var c = string.charCodeAt(n);
                if (c < 128) {
                    utftext += String.fromCharCode(c);
                } else if ((c > 127) && (c < 2048)) {
                    utftext += String.fromCharCode((c >> 6) | 192);
                    utftext += String.fromCharCode((c & 63) | 128);
                } else {
                    utftext += String.fromCharCode((c >> 12) | 224);
                    utftext += String.fromCharCode(((c >> 6) & 63) | 128);
                    utftext += String.fromCharCode((c & 63) | 128);
                }

            }
            return utftext;
        };

        // private method for UTF-8 decoding
        utf8Decode = function (utftext) {
            var string = "";
            var i = 0;
            var c1;
            var c2;
            var c = c1 = c2 = 0;
            while (i < utftext.length) {
                c = utftext.charCodeAt(i);
                if (c < 128) {
                    string += String.fromCharCode(c);
                    i++;
                } else if ((c > 191) && (c < 224)) {
                    c2 = utftext.charCodeAt(i + 1);
                    string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
                    i += 2;
                } else {
                    c2 = utftext.charCodeAt(i + 1);
                    var c3 = utftext.charCodeAt(i + 2);
                    string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
                    i += 3;
                }
            }
            return string;
        };
    },
    /*
     *   日期格式化
     */
    dateFormat:function(time) {
        if (time) {
            var date = new Date(time);
            var month = date.getMonth() + 1 < 10 ? "0" + (date.getMonth() + 1) : date.getMonth() + 1;
            var currentDate = date.getDate() < 10 ? "0" + date.getDate() : date.getDate();
            return date.getFullYear() + "-" + month + "-" + currentDate;
        }
        return "";
    },
    /* 获取上一个月
     *
     * @date 格式为yyyy-mm-dd的日期，如：2014-01-25
     * @return "2013-12-25"
     */
    getPreMonth:function(date) {
        var arr = date.split('-');
        var year = arr[0], month = arr[1], day = arr[2];
        var days = new Date(year, month, 0);
        days = days.getDate();
        var year2 = year, month2 = parseInt(month) - 1;
        if (month2 == 0) {
            year2 = parseInt(year2) - 1;
            month2 = 12;
        }
        var day2 = day, days2 = new Date(year2, month2, 0);
        days2 = days2.getDate();
        if (day2 > days2) {
            day2 = days2;
        }
        if (month2 < 10) {
            month2 = '0' + month2;
        }
        var t2 = year2 + '-' + month2 + '-' + day2;
        return t2;
    } ,
    /* 获取下一个月
     *
     * @date 格式为yyyy-mm-dd的日期，如：2014-01-25
     * @return "2014-02-25"
     */
    getNextMonth:function (date) {
        var arr = date.split('-');
        var year = arr[0], month = arr[1], day = arr[2];
        var days = new Date(year, month, 0);
        days = days.getDate();
        var year2 = year, month2 = parseInt(month) + 1;
        if (month2 == 13) {
            year2 = parseInt(year2) + 1;
            month2 = 1;
        }
        var day2 = day, days2 = new Date(year2, month2, 0);
        days2 = days2.getDate();
        if (day2 > days2) {
            day2 = days2;
        }
        if (month2 < 10) {
            month2 = '0' + month2;
        }
        var t2 = year2 + '-' + month2 + '-' + day2;
        return t2;
    },
    /*
     *   日期比较
     */
    dateCompare:function (startTime, endTime) {
        var start = new Date(startTime.replace("-", "/").replace("-", "/"));
        var end = new Date(endTime.replace("-", "/").replace("-", "/"));
        if (start && end && start.getTime() > end.getTime()) {
            //timeCompareText:"起始时间必须小于截止时间！",
            return false;
        }
        return true;
    },
    /*
     *   uuid
     */
    uuid: {
        set:function () {
            var value;
            if (this.isValid(arguments[0])) {
                value = arguments[0];
            } else {
                value = this.empty();
            }
            $(this).data("value", value);
            return value;
        },
        empty:function () {
            return "00000000-0000-0000-0000-000000000000";
        },
        isEmpty:function (uid) {
            return uid == EUI.Common.uuid.empty() || typeof (uid) == 'undefined' || uid == null || uid == '';
        },
        isValid:function (value) {
            var rGx = new RegExp("\\b(?:[A-F0-9]{8})(?:-[A-F0-9]{4}){3}-(?:[A-F0-9]{12})\\b");
            return rGx.exec(value) != null;
        },
        newUuid:function () {
            var value;
            if (arguments.length == 1 && this.isValid(arguments[0])) {
                $(this).data("value", arguments[0]);
                value = arguments[0];
                return value;
            }
            var res = [], hv;
            var rgx = new RegExp("[2345]");
            for (var i = 0; i < 8; i++) {
                hv = (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
                if (rgx.exec(i.toString()) != null) {
                    if (i == 3) { hv = "6" + hv.substr(1, 3); }
                    res.push("-");
                }
                res.push(hv.toUpperCase());
            }
            value = res.join('');
            $(this).data("value", value);
            return value;
        },
        value:function () {
            if ($(this).data("value")) {
                return $(this).data("value");
            }
            var val = this.newUuid();
            $(this).data("value", val);
            return val;
        }
    },
    /*
     *   数值计算
     */
    number:{
        /**
         * 把错误的数据转正
         * strip(0.09999999999999998)=0.1
         */
        strip:function (num, precision) {
            precision=precision||12;
            return +parseFloat(num.toPrecision(precision));
        },
        /**
         * Return digits length of a number
         * @param {*number} num Input number
         */
        digitLength:function (num) {
            // Get digit length of e
            var eSplit = num.toString().split(/[eE]/);
            var len = (eSplit[0].split('.')[1] || '').length - (+(eSplit[1] || 0));
            return len > 0 ? len : 0;
        },
        times:function (num1, num2) {
            var num1Changed = Number(num1.toString().replace('.', ''));
            var num2Changed = Number(num2.toString().replace('.', ''));
            var baseNum = this.digitLength(num1) + this.digitLength(num2);
            return num1Changed * num2Changed / Math.pow(10, baseNum);
        },
        plus:function (num1, num2) {
            var baseNum = Math.pow(10, Math.max(this.digitLength(num1), this.digitLength(num2)));
            return (this.times(num1, baseNum) + this.times(num2, baseNum)) / baseNum;
        },
        minus:function (num1, num2) {
            var baseNum = Math.pow(10, Math.max(this.digitLength(num1), this.digitLength(num2)));
            return (num1 * baseNum - num2 * baseNum) / baseNum;
        },
        divide:function (num1, num2) {
            var num1Changed = Number(num1.toString().replace('.', ''));
            var num2Changed = Number(num2.toString().replace('.', ''));
            return this.times((num1Changed / num2Changed), Math.pow(10, this.digitLength(num2) - this.digitLength(num1)));
        },
        /**
         * 四舍五入
         */
        round:function(num, ratio) {
            ratio=ratio||2;
            var base = Math.pow(10, ratio);
            return this.divide(Math.round(this.times(num, base)), base);
        }
    },




    /*
     *   几个常用字符串hash算法的
     */
   /*
   //nodeJs中使用
   additive: function (key, prime) {
        key = key instanceof Buffer ? key : new Buffer(key);
        prime = prime == undefined ? 0xffffffff : prime;
        for (var hash = key.length, i = 0; i < key.length; i++) {
            hash += key[i];
        }
        return (hash % prime);
    },
    rotating: function (key) {
        key = key instanceof Buffer ? key : new Buffer(key);
        for (var hash = key.length, i = 0; i < key.length; ++i) {
            hash = (hash << 4) ^ (hash >> 28) ^ key[i];
        }
        return hash;
    },

    bernstein: function (key, prime) {
        key = key instanceof Buffer ? key : new Buffer(key);
        prime = prime == undefined ? 0xffffffff : prime;
        var hash = 0;
        for (i = 0; i < key.length; ++i) {
            hash = (hash << 5 + hash) + key[i];
        }
        return hash;
    },

    fnv: function (key) {
        key = key instanceof Buffer ? key : new Buffer(key);
        var p = 16777619, hash = 0x811C9DC5;
        for (var i = 0; i < key.length; i++) {
            hash = (hash * p) ^ key[i];
        }
        hash += hash << 13;
        hash ^= hash >> 7;
        hash += hash << 3;
        hash ^= hash >> 17;
        hash += hash << 5;
        return hash;
    },

    fnv1a: function (key) {
        key = key instanceof Buffer ? key : new Buffer(key);
        var p = 16777619, hash = 0x811C9DC5;
        for (var i = 0; i < key.length; i++) {
            hash = (hash ^ key[i]) * p;
        }
        hash += hash << 13;
        hash ^= hash >> 7;
        hash += hash << 3;
        hash ^= hash >> 17;
        hash += hash << 5;
        return hash;
    },*/
   hash:{
        hashCode: function(str){
            var hash = 0;
            if (str.length == 0) return hash;
            for (i = 0; i < str.length; i++) {
                char = str.charCodeAt(i);
                hash = ((hash<<5)-hash)+char;
                hash = hash & hash; // Convert to 32bit integer
            }
            return hash;
        },
        djb2Code: function (str){
            var hash = 5381;
            for (i = 0; i < str.length; i++) {
                char = str.charCodeAt(i);
                hash = ((hash << 5) + hash) + char; /* hash * 33 + c */
            }
            return hash;
        },

        sdbmCode: function (str){
            var hash = 0;
            for (i = 0; i < str.length; i++) {
                char = str.charCodeAt(i);
                hash = char + (hash << 6) + (hash << 16) - hash;
            }
            return hash;
        },

        loseCode: function (str){
            var hash = 0;
            for (i = 0; i < str.length; i++) {
                char = str.charCodeAt(i);
                hash += char;
            }
            return hash;
        },
   },

    /**
     * 通过汇率计算
     * @param currency 对象 {sourceMoney：待计算货币金额,fromCurrencyCode: 待转换货币的货币代码，toCurrencyCode:转换到货币的货币代码}
     * @param exchangeRate 汇率对象 { exchangeRate  fixExchangeRate  fromExchangeUnit  toExchangeUnit }
     * @param reverse 是否逆向转换
     * @returns 转换后金额
     */
    calcMoney: function (currency, exchangeRate, reverse) {
        if(!currency.sourceMoney){
            return 0;
        }
        if (currency.fromCurrencyCode == currency.toCurrencyCode) {
            return currency.sourceMoney;
        }
        if (!exchangeRate.toExchangeUnit || !exchangeRate.exchangeRate || !exchangeRate.fromExchangeUnit) {
            return currency.sourceMoney;
        }
        var destMoney;
        if(reverse){
            //逆向转换 money /toExchangeUnit /exchangeRate * fromExchangeUnit
            destMoney = this.number.divide(this.number.divide(currency.sourceMoney, exchangeRate.toExchangeUnit),exchangeRate.exchangeRate);
            destMoney = this.number.times(destMoney, exchangeRate.fromExchangeUnit);
        }else{
            //正向转换 money * toExchangeUnit * exchangeRate / fromExchangeUnit
            destMoney = this.number.times(this.number.times(currency.sourceMoney, exchangeRate.toExchangeUnit),exchangeRate.exchangeRate);
            destMoney = this.number.divide(destMoney, exchangeRate.fromExchangeUnit);
        }
        return this.number.round(destMoney);
    },
    /**
     * 延时
     * @param numberMillis 延时毫秒数
     */
    sleep:function (numberMillis) {
        var now = new Date();
        var exitTime = now.getTime() + numberMillis;
        while (true) {
            now = new Date();
            if (now.getTime() > exitTime)
                return;
        }
    },
    //计算代码耗时
    // test
    /*
     Timer.start("div");
     Timer.stop("div");
     console.log("the time is:"+Timer.getTime(div));
     */
    timer: {
        data:{},
        start:function(key){
            this.data[key] = new Date().getTime();
        },
        stop:function(key){
            var time=this.data[key];
            if(time){
                this.data[key] = new Date().getTime()-time;
            }
        },
        getTime:function(key){
            return this.data[key];
        }
    }

};